package cn.remex.wechat;

import cn.remex.RemexConstants;
import cn.remex.contrib.appbeans.DataCvo;
import cn.remex.contrib.appbeans.DataRvo;
import cn.remex.core.*;
import cn.remex.core.exception.ServiceCode;
import cn.remex.core.reflect.ReflectUtil;
import cn.remex.core.util.*;
import cn.remex.db.Database;
import cn.remex.db.DbRvo;
import cn.remex.db.model.SysConfig;
import cn.remex.db.model.SysUser;
import cn.remex.db.sql.WhereGroupOp;
import cn.remex.web.service.BsRvo;
import cn.remex.web.service.BusinessService;
import cn.remex.web.service.appbeans.AsyncCvo;
import cn.remex.web.service.appbeans.AsyncRvo;
import cn.remex.wechat.beans.WeChatUserInfo;
import cn.remex.wechat.beans.WeChatUserLocation;
import cn.remex.wechat.beans.messages.TemplateMessage;
import cn.remex.wechat.beans.messages.TemplateMsg;
import cn.remex.wechat.config.WeChatApp;
import cn.remex.wechat.event.*;
import cn.remex.wechat.models.*;
import cn.remex.wechat.utils.LocationUtils;
import cn.remex.wechat.utils.coordinate.Gps;
import cn.remex.wechat.utils.coordinate.PositionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static cn.remex.RemexConstants.EffectFlag.VALID;
import static cn.remex.RemexConstants.LocationCollectionChannel.WECHAT_SUBSCRIPTION;
import static cn.remex.RemexConstants.UserType.ADMIN;
import static cn.remex.core.exception.ServiceCode.FAIL;
import static cn.remex.core.exception.ServiceCode.SUCCESS;
import static cn.remex.core.util.Judgment.nullOrBlank;
import static cn.remex.db.rsql.RsqlConstants.SysStatusEnum.Doing;
import static cn.remex.db.rsql.RsqlConstants.SysStatusEnum.Finish;
import static cn.remex.db.sql.WhereRuleOper.equal;
import static cn.remex.db.sql.WhereRuleOper.startsWith;
import static cn.remex.web.service.BusinessService.ServiceType.AsyncService;

/**
 * 名称：
 * 缩写：
 * 用途：
 * Created by guoqi on 2016/3/1.
 */
@BusinessService
@Component
@EnableAsync
public class WeChatService extends RemexStartupListener {

	Logger logger = LoggerFactory.getLogger(WeChatService.class);
	@BusinessService(authLevel = ADMIN)
	public void initWeChat(){
		WeChat.initWeChat();
	}

	@Override
	public void onRemexStartupEvent(RemexStartupEvent paramApplicationEvent) {
		initWeChat();
	}

	@BusinessService(authLevel = ADMIN)
	public Object wechatApps(){
		Map<String, String> wechatApps = new HashMap<>();
		WeChat.getWeChatAppMap().forEach((appid, app)-> wechatApps.put(nullOrBlank(app.getConfig().getAppName())?appid:app.getConfig().getAppName(), appid));
		return wechatApps;
	}

    @BusinessService(authLevel = ADMIN)
    public Object downloadWxMenu(String appid,String agentid){
	    WeChatApp curApp = WeChat.getWeChatApp(appid, nullOrBlank(agentid)?"0":agentid);
	    Assert.notNullAndEmpty(curApp, FAIL,"未查找到对应的wxapp,appid="+appid+";agentid="+agentid);
    	return curApp.menuGet();
    }
    @BusinessService(authLevel = ADMIN)
    public Object uploadWxMenu(String appid,String agentid,String menusJson){
	    WeChatApp curApp = WeChat.getWeChatApp(appid, nullOrBlank(agentid)?"0":agentid);
	    Assert.notNullAndEmpty(curApp, FAIL,"未查找到对应的wxapp,appid="+appid+";agentid="+agentid);
    	return curApp.menuCreate(menusJson);
    }

	@BusinessService(authLevel = ADMIN)
	public Object saveWeChatConfig(WeChatAppConfig config){
		return WeChat.saveWeChatAppConfig(config);
	}
	@BusinessService(authLevel = ADMIN)
	public Object delWeChatConfig(WeChatAppConfig config){
		return WeChat.delWeChatAppConfig(config);
	}
	@BusinessService(authLevel = ADMIN)
	public Object weChatConfigs(){
		return WeChat.weChatAppConfigs();
	}



    @BusinessService(needAuth = false)
    public BsRvo redirectWxMenu(String code, String state, String quickCheck){
    	//code 是微信回调的授权code
        //state 是微信菜单回调时携带的参数
	    Assert.notNullAndEmpty(state, FAIL,"微信OAuth2.0验证接口URL跳转时state不得为空");
	    String[] originStates = state.split(";");//state参数以分号;分割，第一个为state，第二个为appid，第三个为agentid
	    state = originStates[0];
	    String appid = originStates.length > 1 ? originStates[1] : null;
	    String agentid = originStates.length > 2 ? originStates[2] : null;
	    WeChatApp curWeChatApp = WeChat.getWeChatApp(appid,agentid);
	    String origin_redirect = curWeChatApp.obtainStateRedirect(state);

	    if(nullOrBlank(code) && "true".equals(quickCheck)){
		    //在没有code的时候本地验证cookie，通过则不用微信的跳转了
	    	if(RemexContext.obtainCurUser() != null){
			    RemexConstants.logger.info("===================微信菜单回调，缓存存在快速跳转,state_redirect={},==================",origin_redirect);
			    return new BsRvo(SUCCESS, "微信菜单回调服务正常，绑定用户登录成功", null, RemexConstants.ResponseContentType.redirect, origin_redirect);
		    }else{
			    String redirectUrl = curWeChatApp.oauth2_authorize("http%3a%2f%2f" + curWeChatApp.getConfig().getRedirectDomain() + "%2fsmvc%2fWechatService%2fredirectWxMenu.json", state+";"+appid+";"+agentid);
			    RemexConstants.logger.info("===================微信菜单回调，快速跳转未通过,state_redirect={},微信url{}==================",origin_redirect,redirectUrl);
			    return new BsRvo(SUCCESS, "微信菜单回调服务正常，快速验证未通过", null, RemexConstants.ResponseContentType.redirect, redirectUrl);
		    }
	    }else{
		    //正常通过code微信验证
	        RemexConstants.logger.info("===================微信菜单回调,code={};state={},==================",code,state);
		    Assert.notNullAndEmpty(code, FAIL,"微信OAuth2.0验证接口URL跳转时code不得为空");
	        //默认通过openid登录

		    String openid = curWeChatApp.obtainOpenidByCode(code);////"o1dzwv1e8Nl1Eq_OA3jvBScf0tAg";}
		    SysUser curSysUser = curWeChatApp.obtainSysUserByOpenId(openid);
		    if (nullOrBlank(curSysUser)) {
			    String state_redirect = curWeChatApp.obtainStateRedirect("WX_LOGIN") + "?redirectUri=" + origin_redirect;
			    CoreSvo.putCookie("openId", openid);//openId回填前端页面，用于后续的绑定
			    RemexConstants.logger.info("===================微信菜单回调，需要登录,state_redirect={},==================",state_redirect);
			    return new BsRvo(SUCCESS, "微信菜单回调服务正常，该用户没有绑定，需要登录绑定", null, RemexConstants.ResponseContentType.redirect, state_redirect);
		    } else {
			    RemexContext.placeToken(curSysUser);//登录成功
			    RemexConstants.logger.info("===================微信菜单回调，正常跳转,state_redirect={},==================",origin_redirect);
			    return new BsRvo(SUCCESS, "微信菜单回调服务正常，绑定用户登录成功", null, RemexConstants.ResponseContentType.redirect, origin_redirect);
		    }
	    }

    }

	/**
	 *
	 * 为兼容微信企业号/企业微信的oauth回调参数处理不一致的问题，新增了redirect方法，将第一个state部分的路径拆分为两部分，避免了井号的出现
	 * @param code	微信回调code
	 * @param state	微信回调state
	 * @param quickCheck quickCheck
	 * @return 返回对应地址的跳转
	 */
	@BusinessService(needAuth = false)
	public BsRvo redirectWxMenuWork(String code, String state, String quickCheck){

		String[] originStates = state.split(";");//state参数以分号;分割，第一个为state的contextRoot部分，第二个为state的path部分，第三个为appid，第四个为agentid
		if(originStates.length > 1){
			StringBuilder stateBuilder = new StringBuilder();
			stateBuilder.append(originStates[0]).append("/#").append(originStates[1]);
			for(int i = 2; i < originStates.length; i++){
				stateBuilder.append(";").append(originStates[i]);
			}
			state = stateBuilder.toString();
		}

		return redirectWxMenu(code, state, quickCheck);
	}

    @BusinessService(authLevel = ADMIN)
    public BsRvo weixinUsers(DataCvo dataCvo) {
        DbRvo userInfos = dataCvo.obtainDbCvo(WeChatUser.class).ready().query();
        return new DataRvo(userInfos);
    }
	@BusinessService(type = AsyncService)
	public BsRvo updateAllUserInfoWithWeChat(String appid,String agentId, AsyncCvo asyncCvo){
        return new AsyncRvo().start(asyncRvo -> {
        	Param<Integer> countUpdated = new Param<>();
	        countUpdated.param = 0;
	        WeChat.getWeChatAppExt().everyWeChatUserOpenId(openId->{
	            updateUserInfoWithWeChat(appid,agentId, openId);
	            asyncRvo.update(Doing, countUpdated.param++, "[" + asyncRvo.getAsyncStatus().getKey() + "]更新微信用户: " + countUpdated.param);
            });
	        asyncRvo.update(Finish, countUpdated.param, "[" + asyncRvo.getAsyncStatus().getKey() + "]更新微信用户: " + countUpdated.param);

	        return asyncRvo;
        });
    }
	@BusinessService
	public BsRvo updateUserInfoWithWeChatByOpenId(String appid,String agentId, String openId){
		updateUserInfoWithWeChat(appid,agentId, openId);
		return new BsRvo(SUCCESS,"用户微信信息更新！","");
	}
	@BusinessService
	public BsRvo sendMsgByOpenId(String openid, String msgContent){
		WeChatUser weChatUser = Database.createDbCvo(WeChatUser.class)
				.filterBy(WeChatUser::getOpenid, equal, openid)
				.withBase(WeChatUser::getId)
				.withBase(WeChatUser::getSysUser,su->su.withBase())
				.ready().queryBean();

		Assert.notNullAndEmpty(weChatUser, FAIL, "微信用户身份或用户身份缺失");

		if(true || System.currentTimeMillis()-weChatUser.getWeixinLastTime()<23*3600*1000) {
			return new BsRvo(WeChat.getWeChatAppExt().sendCustomWeChatMsg(openid, msgContent)? SUCCESS:FAIL,"消息发送");
		}else
			return new BsRvo(sendTemplateMsg(openid, msgContent)? SUCCESS:FAIL,"消息发送");
	}
	@BusinessService
	public Object downloadMedia(String mediaId, String appId, String agentId){
		Param<String> urlVo = new Param<>();
		WeChatApp curWeChatApp = WeChat.getWeChatApp(appId, agentId);
		WeChatAppConfig curWeChatAppConfig = curWeChatApp.getConfig();
		curWeChatApp.media_get(mediaId,inputStream->{
			urlVo.param = WebDavFileUtil.uploadFileByPutWithSuffix(inputStream, ".jpg");

			Database.insert(WeChatMedia.class)
					.assignColumn(WeChatMedia::getAppid, curWeChatAppConfig.getAppid())
					.assignColumn(WeChatMedia::getAgentid, curWeChatAppConfig.getAgentid())
					.assignColumn(WeChatMedia::getMediaId, mediaId)
					.assignColumn(WeChatMedia::getSavedUrl, urlVo.param)
					.execute()
			;
		});
		return MapHelper.toMap("savedUrl", urlVo.param);
	}
	@BusinessService
	public Object signJsApiBySHA(String url,String appId,String agentId) {
		return WeChat.getWeChatApp(appId,agentId).signJsApiBySHA(url);
	}



    @EventListener@Async // spring异步事件
    public void dealWeChatEvent(WeChatEvent event) {
        RemexConstants.logger.info("异步处理WeChatEvent，openId= {}",event.getFromUserName());

	     //保存所有的微信信息
        //event eventKey ticket 三个字段必须保存，其中ticket再微信二维码扫描登录中已被使用
	    // TODO 5s没有返回则微信会重发，一共三次，需要消息重排和去重
	    WeChatNotify weChatNotify = new WeChatNotify(event.getMsgType(), event.getFromUserName(), event.getToUserName(), new Date().getTime()/1000,
			    event.getEvent(), event.getEventKey(),event.getTicket() );
	    Database.getSession().store(weChatNotify);

        //更新微信访问的最后时间
	    WeChatUser weChatUser = Database.createDbCvo(WeChatUser.class).filterBy(WeChatUser::getOpenid, equal, event.getFromUserName()).ready().queryBean();
        if(!nullOrBlank(weChatUser)) {
	        weChatUser.setWeixinLastTime(System.currentTimeMillis()/1000);
	        Database.getSession().store(weChatUser);
        }

	    //TODO 更新用户信息，不用每次都更新
	    //updateUserInfoWithWeChat(event.getFromUserName());
    }
    /**
     * 微信微信与用户绑定
     *
     * //此方法不能跑出异常，否则微信端会出错。
     *
     * 关注事件(直接关注 eventKey为空，没有关注时通过群生成的二维码关注 eventKey为scene_id，没有关注时通过平台生成的二位码关注 比如登录的二位码，eventKey为qrscene_+平台指定的参数)
     * 关注事件中，如果是通过平台用用户id生成的二位码进入的，则可以绑定用户
     * @param event 微信订阅事件
     */
    @EventListener@Async // spring异步事件
    public void dealSubscribeForBindUser(WeChatSubscribeEvent event) {
        RemexConstants.logger.info("异步处理WeChatSubscribeEvent，openId={};userId(sceneKey)={}",event.getOpenId(),event.getSceneKey());
        String openId = event.getOpenId();
        String userId = event.getSceneKey();
        bindUser(event.getAppid(),event.getAgentid(), openId, userId);//如果没有userid就不绑定,仅保存wechatUser的信息
	    WeChat.getWeChatAppExt().sendnewCustomWeChatMsg(openId,"MNG_oY3AIdsyPiURq506J-YNSGtIwlWtRKjBmnjaK6Q");
    }

    public static final String weixinLoginQrcodeUrl_SceneId = "100"; // 微信登陆二维码场景
    @EventListener@Async
    public void dealScanEventForBindUserOrWeChatLogin(WeChatScanEvent event) {
        RemexConstants.logger.info("异步处理 WeChatScanEvent，openId={};eventKey={}",event.getOpenId(),event.getEventKey());
        //本系统定义了几个二位码的使用场景：
        //1. QR_SCENE为临时，weixinLoginQrcodeUrl_SceneId == eventKey -> 微信登录（目前Teep端在使用，CET没有使用）
        //2. 【此为默认选项】QR_LIMIT_STR_SCENE为永久的字符串参数值, 在AdminBs.bindWeixin 中通过userid生成二位码，实现用户绑定
        if (weixinLoginQrcodeUrl_SceneId.equals(event.getEventKey())) {
            //TODO 此分支的代码还需要在登录逻辑中分离 所有的时间均保存到WeChatNotify表中，后续可以考虑放到缓存中
//            //扫码登录
//            SysUser curUser = Database.createDbCvo(SysUser.class)
//                    .filterBy(SysUser::getOpenid, eq, event.getOpenId())
//                    .ready().queryBean();
//            if(!Judgment.nullOrBlank(curUser)){
//                String tickets = event.getTickets();
//                RemexContext.wxusers.put(tickets, curUser);//登陆成功,微信扫描成功
//            }
	        //TODO 通过WeChatEvent事件将扫描信息保存到WeChatNotify表中，再UserService.loginByWeiXin中读取该表的信息进行微信登录，避免了分布式缓存的问题。登录属于非平凡操作，直接读库问题不大
        }else if(!nullOrBlank(event.getEventKey())){
            //绑定用户，默认eventKey不为空则尝试绑定
            RemexConstants.logger.info("准备绑定用户openId={};eventKey={}",event.getOpenId(),event.getEventKey());
            bindUser(event.getAppid(),event.getAgentid(), event.getOpenId(), event.getEventKey());
        }else{
            //eventKey 为空的事件暂不处理
        }
    }
    @EventListener@Async
    public void dealUnsubscribeForDismissUser(WeChatUnsubscribeEvent event) {
        RemexConstants.logger.info("异步处理 WeChatUnsubscribeEvent，openId={};userId(sceneKey)={}",event.getOpenId(),event.getSceneKey());
        dismissedBindUser(event.getOpenId());
    }
    @EventListener@Async
    public void dealWeChatTextEvent(WeChatTextEvent event) {
        WeChatMsg msg = Database.createDbCvo(WeChatMsg.class).filterBy(WeChatMsg::getMsgId, equal, event.getMsgId()).ready().queryBean();
		String appid = event.getAppid();
		if(null==msg){//避免重复保存
            msg = new WeChatMsg();
            msg.setMsgId(event.getMsgId());
            msg.setWxCreateTime(event.getCreateTime()*1000);
            msg.setFromUserName(event.getFromUserName());
            msg.setToUserName(event.getAppid());
            msg.setContent(event.getContent());
            Database.getSession().store(msg);
        }
        if(appid.equals(msg.getToUserName())){//如果是客户给公众号发消息

			SysConfig config=Database.select(SysConfig.class).filterBy(SysConfig::getKey,equal,"autoReply_"+event.getAppid()+"_"+event.getAgentid())
					.rowCount(1)
					.execute().obtainBean();
			if(config!=null&&"OPEN".equals(config.getValue())){
				//回复消息
				WeChatAutoReply autoReply = getReply(event.getContent());
				if(autoReply!=null&&Judgment.notEmpty(autoReply.getContent())){
					WeChat.getWeChatAppExt(appid,event.getAgentid()).sendCustomWeChatMsg(event.getFromUserName(), autoReply.getContent());
				}
			}
		}

    }
	@EventListener@Async
	public void dealWeChatClickEvent(WeChatClickEvent event) {
		String eventKey = event.getEventKey();
		String msg ;
		if(!nullOrBlank(eventKey) && !nullOrBlank(msg = WeChat.getWeChatApp().obtainClickEventMsg(eventKey))){
			WeChat.getWeChatAppExt(event.getAppid(),event.getAgentid()).sendCustomWeChatMsg(event.getFromUserName(), msg);
		}
	}
	@EventListener@Async
	public void dealWeChatLocationEvent(WeChatLocationEvent event) {
		logger.info("处理获取地理位置事件");
		String latitude = event.getLatitude();
		logger.info("latitude:{}",latitude);
		String longitude = event.getLongitude();
		logger.info("longitude:{}",longitude);
		WeChatUserLocation weChatUserLocation = new WeChatUserLocation();
		weChatUserLocation.setLatitude(latitude);
		weChatUserLocation.setLongitude(longitude);
		weChatUserLocation.setFromUserName(event.getFromUserName());
		weChatUserLocation.setToUserName(event.getToUserName());
		weChatUserLocation.setEventKey(event.getEventKey());
		weChatUserLocation.setPrecision(event.getPrecision());
		weChatUserLocation.setMsgCreateTime(new Date(event.getCreateTime()*1000));
		weChatUserLocation.setCollectionChannel(WECHAT_SUBSCRIPTION);
		//		String address = LocationUtils.dealLatitudeAndLongitudeGetAddr(latitude,longitude);
		Gps gps= PositionUtil.gps84_To_Gcj02(Double.valueOf(latitude),Double.valueOf(longitude));
		String address = LocationUtils.getAddrByLongitudeAndLatitude(String.valueOf(gps.getWgLon()),String.valueOf(gps.getWgLat()));

		weChatUserLocation.setAddress(address);
		Database.store(weChatUserLocation).execute();

	}




	public static boolean bindUser(String appid,String agentId, String openId,String userId) {
		RemexConstants.logger.info("绑定微信用户，userId={}；openId={}" ,userId, openId);
		SysUser user = null;
		if(!Judgment.nullOrBlank(userId))
			user = Database.createDbCvo(SysUser.class).filterById(userId).ready().queryBean();

		if (null == user) {
			RemexConstants.logger.info("绑定微信用户时，没有查询到用户，userID={}" , userId);
		}
		return bindUser(appid,agentId, openId, user);
	}
    public static boolean bindUser(String appid,String agentId, String openId,SysUser user) {
        Assert.notNullAndEmpty(openId, ServiceCode.OPENID_INVALID,"绑定微信用户时openId不能为空");
        try {
//            boolean openIdUsed = Database.select(SysUser.class)
//		            .withBase(SysUser::getId)
//		            .filterBy(SysUser::getOpenid, equal, openId).execute().getRecordCount() > 0;

	        RemexConstants.logger.info("通过微信绑定用户,读取远程微信端用户的信息，openId={}",openId);
	        WeChatUserInfo weChatUserInfo = WeChat.getWeChatApp(appid,agentId).userInfo(openId);
	        if (nullOrBlank(weChatUserInfo)) {
		        RemexConstants.logger.info("没有获取到微信用户信息，weChatUserInfo={}", JsonHelper.toJsonString(weChatUserInfo));
		        return false;
	        }

	        RemexConstants.logger.info("通过微信绑定用户,读取本地微信用户的信息，openId={}",openId);
	        WeChatUser curWeChatUser = Database.select(WeChatUser.class)
			        .withBase().withModel(WeChatUser::getSysUser)
			        .filterBy(WeChatUser::getOpenid, equal, openId).execute().obtainBean();

	        //保存微信用户信息
	        if(null==curWeChatUser) {
		        RemexConstants.logger.info("通过微信绑定用户,创建微信用户，openId={}",openId);
		        if(Judgment.notEmpty(weChatUserInfo.getUnionid())){
					curWeChatUser = Database.select(WeChatUser.class)
							.withBase().withModel(WeChatUser::getSysUser)
							.filterBy(WeChatUser::getUnionid, equal, weChatUserInfo.getUnionid())
							.rowCount(1)
							.execute().obtainBean();
				}
				if(curWeChatUser == null){
					curWeChatUser = new WeChatUser();
				}else{
					curWeChatUser.setOpenid(openId);
				}

	        }
	        ReflectUtil.copyProperties(curWeChatUser, weChatUserInfo);//响应回来的用户信息更新到数据的微信用户表中
	        if(!nullOrBlank(weChatUserInfo.getSubscribe_time()))
	        	curWeChatUser.setSubscribeTime(Long.parseLong(weChatUserInfo.getSubscribe_time()));
	        //用户没有绑定或者用户openid和原id一致的情况下，都更新信息,其他的返回
            if (!nullOrBlank(curWeChatUser.getSysUser()) && user!=null && user.getId().equals(curWeChatUser.getSysUser().getId())) {  //用户已经绑定， 或者  openId 已经被使用
		        Database.store(curWeChatUser).execute().assertEffectOneRow(FAIL, "保存用户微信身份信息失败");
	            RemexConstants.logger.info("用户已绑定微信，且与当前openId不一致，不进行绑定操作，openId={}, 已绑定用户={}, 待绑定用户={}",openId,curWeChatUser.getSysUser().getId(),user.getId());
                return false;
            }else if(null!=user){
	            curWeChatUser.setSysUser(user);
		        Database.store(curWeChatUser).execute().assertEffectOneRow(FAIL, "保存用户微信身份信息失败");
	            RemexConstants.logger.info("用户已成功绑定微信，openId={}, 已绑定用户={}", openId, curWeChatUser.getSysUser().getId());
	            return true;
            }else {
		        Database.store(curWeChatUser).execute().assertEffectOneRow(FAIL, "保存用户微信身份信息失败");
	            RemexConstants.logger.info("用户未成功绑定微信,仅保存微信用户信息，openId={}", openId);
	            return false;

            }
        } catch (Throwable throwable) {
            RemexConstants.logger.error("绑定用户异常！", throwable);
            return false;
        }
    }

    public static boolean dismissedBindUser(String openId) {
	    WeChatUser user = Database.createDbCvo(WeChatUser.class)
			    .withBase(WeChatUser::getId)
			    .withModel(WeChatUser::getSysUser)
			    .filterBy(WeChatUser::getOpenid, equal, openId).ready().queryBean();
        if (nullOrBlank(user) || nullOrBlank(user.getSysUser())) {
            return false;
        }
	    Database.update(WeChatUser.class)
			    .filterById(user.getId())
			    .assignNull(WeChatUser::getSysUser)
			    .execute().assertEffectOneRow(FAIL, "解绑用户信息有误");

	    return true;
    }
	private WeChatUser updateUserInfoWithWeChat(String appkey,String agentId, String openId) {
		WeChatUserInfo weChatUserInfo = WeChat.getWeChatApp(appkey,agentId).userInfo(openId);

		if(null!=weChatUserInfo){
			//通过openid或unionid查看用户是否存在
			WeChatUser curUserInfo = Database.createDbCvo(WeChatUser.class)
					.filterOper(WhereGroupOp.OR)
					.filterBy(WeChatUser::getUnionid, equal,weChatUserInfo.getUnionid())
					.filterBy(WeChatUser::getOpenid, equal, openId).ready().queryBean();
			if(nullOrBlank(curUserInfo)) {
				curUserInfo = new WeChatUser();
			}
			ReflectUtil.copyProperties(curUserInfo,weChatUserInfo);//相同字段直接拷贝过去
			curUserInfo.setSubscribeTime(Long.parseLong(weChatUserInfo.getSubscribe_time()));//不同的字段
			Database.getSession().store(curUserInfo).getStatus();
			return curUserInfo;
		}else
			return null;
	}

	public static boolean sendTemplateMsg(String openId, String remarkMsg){
		TemplateMessage templateMessage = new TemplateMessage();
		//模板Id,在模板信息中
		templateMessage.setTemplate_id(((Map<String,String>)RemexApplication.getBean("weixin")).get("msgTemplate"));
		templateMessage.setTouser(openId);
		TemplateMsg first = new TemplateMsg(remarkMsg,"#8cc474");
		TemplateMsg keyword1 = new TemplateMsg("服务消息","#173177");
		TemplateMsg keyword2 = new TemplateMsg(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),"#173177");
		TemplateMsg remark = new TemplateMsg("如有需要可微信留言，我公司客服将及时联系您。","#173177");
		LinkedHashMap<String, TemplateMsg> data = new LinkedHashMap<>();
		data.put("first",first);
		data.put("keyword1",keyword1);
		data.put("keyword2",keyword2);
		data.put("remark",remark);
		templateMessage.setData(data);
		return WeChat.getWeChatAppExt().messageTemplateSend(templateMessage);
	}


	@BusinessService
	public Object operateAutoReply(WeChatAutoReply weChatAutoReply){
		Assert.notNullAndEmpty(weChatAutoReply, FAIL,"自动回复体为空");
		Assert.notNullAndEmpty(weChatAutoReply.getKeywords(), FAIL,"自动回复关键字为空");
		Assert.notNullAndEmpty(weChatAutoReply.getContent(), FAIL,"自动回内容为空");
		weChatAutoReply.setKeywords(weChatAutoReply.getKeywords().replaceAll("；",";"));//将中文标点替换为英文

		WeChatAutoReply dataWeChatAutoReply=null;
		if(Judgment.notEmpty(weChatAutoReply.getId())){//修改

			dataWeChatAutoReply =Database.select(WeChatAutoReply.class).withBase()
					.filterById(weChatAutoReply.getId()).execute().obtainBean();
			Assert.notNullAndEmpty(dataWeChatAutoReply, FAIL,"库中未找到该条记录");
			dataWeChatAutoReply.setKeywords(weChatAutoReply.getKeywords());
			dataWeChatAutoReply.setContent(weChatAutoReply.getContent());
			dataWeChatAutoReply.setReplyStatus(weChatAutoReply.getReplyStatus());

			dataWeChatAutoReply.setUpdateDate(new Date());
		}else{//新增

			weChatAutoReply.setAddDate(new Date());
			dataWeChatAutoReply=weChatAutoReply;
		}

		Database.store(dataWeChatAutoReply).execute().assertEffectOneRow(FAIL,"操作失败");

		return new BsRvo(ServiceCode.SUCCESS,"ok","操作成功");
	}




	public WeChatAutoReply getReply(String question){

		RemexConstants.logger.info("咨询问题:{},开始获取回复答案",question);
		List<WeChatAutoReply> replyList =Database.select(WeChatAutoReply.class).withBase()
				.filterBy(WeChatAutoReply::getReplyStatus,equal,VALID).rowCount(100000).execute().obtainBeans();

		Map<String,WeChatAutoReply> replyMap = new HashMap<>();
		replyList.forEach(reply->{
			if(Judgment.notEmpty(reply.getKeywords())){
				String[] keyWords = reply.getKeywords().split(";");
				for(String keyWord:keyWords){
					if(replyMap.get(keyWord)==null){
						replyMap.put(keyWord,reply);
						RemexConstants.logger.info("咨询问题:{},获取到回复答案{}",question,reply.getContent());
					}
				}
			}

		});

		for(Map.Entry<String,WeChatAutoReply> entry:replyMap.entrySet()){
			if(question.contains(entry.getKey())){
				return entry.getValue();
			}
		}
		RemexConstants.logger.info("咨询问题:{},未获取到回复答案",question);

		return null;

	}

	@BusinessService
	public Object switchAutoReply(String appid,String agentid,String status){
		Assert.notNullAndEmpty(appid, FAIL,"appid为空");
		Assert.notNullAndEmpty(agentid, FAIL,"agentid为空");
		Assert.notNullAndEmpty(status, FAIL,"status为空");
		Assert.isTrue("OPEN".equals(status)||"CLOSE".equals(status), FAIL,"status不合法");
		Database.update(SysConfig.class).assignColumn(SysConfig::getValue,status)
				.filterBy(SysConfig::getKey,equal,"autoReply_"+appid+"_"+agentid)
				.execute().assertEffectOneRow(FAIL,"操作失败");
		return new BsRvo(ServiceCode.SUCCESS,"OK","操作成功");
	}

	@BusinessService
	public Object listAutoReplySwitch(){

		List<SysConfig> switchList = Database.select(SysConfig.class).withBase(sysConfg->{sysConfg.getKey();sysConfg.getValue();})
				.filterBy(SysConfig::getKey,startsWith,"autoReply_")
				.execute().obtainBeans();
		Map<String,Boolean> switchMap= new HashMap<>();
		if(switchList!=null){
			switchList.forEach(sysConfig -> {
				if(switchMap.get(sysConfig.getKey())==null){
					if("OPEN".equals(sysConfig.getValue())){
						switchMap.put(sysConfig.getKey(),true);
					}else{
						switchMap.put(sysConfig.getKey(),false);
					}
				}
			});
		}
		return new BsRvo(ServiceCode.SUCCESS,"OK",switchMap);
	}

}
